﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

// MobiLib, Copyright Mirosław M. Mączka.  All Rights Reserved. This code released under the terms of the Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

namespace MobiLibrary
{
    public partial class MobiLib
    {
        // Main interface
        //
        //
        //
        //
        //
        //==================================================================================================================================
        //
        /// <summary>
        /// zwraca zawartość pola Name z PRC Header
        /// wpisuje do tego pola, max długość 31 bajtów + bajt zerowy
        /// </summary>
        public string Name
        {
            get
            {
                lock (olock)
                {
                    return prcHdr.Name;
                }
            }
            set
            {
                lock (olock)
                {
                    prcHdr.IsDirty = true;
                    String2BytesWA(value, prcHdr.mb.Buffer, 0, 32);
                }
            }
        }
        //
        //
        public DateTime CreationTime
        {
            get
            {
                lock (olock)
                {
                    return prcHdr.dtCreationTime;
                }
            }
            set
            {
                lock (olock)
                {
                    prcHdr.IsDirty = true;
                    prcHdr.dtCreationTime = value;
                }
            }
        }
        //
        public DateTime ModificationTime
        {
            get
            {
                lock (olock)
                {
                    return prcHdr.dtModificationTime;
                }
            }
            set
            {
                lock (olock)
                {
                    prcHdr.IsDirty = true;
                    prcHdr.dtModificationTime = value;
                }
            }
        }
        //
        public DateTime BackupTime
        {
            get
            {
                lock (olock)
                {
                    return prcHdr.dtBackupTime;
                }
            }
            set
            {
                lock (olock)
                {
                    prcHdr.IsDirty = true;
                    prcHdr.dtBackupTime = value;
                }
            }
        }
        //
        //==================================================================================================================================
        //
        /// <summary>
        /// zwraca zawartość pola Full Name
        /// wpisuje do tego pola
        /// </summary>
        public string FullName
        {
            get
            {
                lock (olock)
                {
                    if (null == mfn) return null;
                    return mfn.GetString();
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == mfn) return;
                    mfn.IsDirty = true;
                    mfn.SetString(MetaBuffer, value);
                }
            }
        }
        //
        //==================================================================================================================================
        //
        /// <summary>
        /// zwraca zawartość pola Text Encoding
        /// wpisuje do tego pola (65001 Unicode UTF-8, 1252 Windows Western European languages)
        /// </summary>
        public int TextEncoding
        {
            get
            {
                lock (olock)
                {
                    return mobiHdr.TextEncoding;
                }
            }
            set
            {
                lock (olock)
                {
                    mobiHdr.IsDirty = true;
                    mobiHdr.TextEncoding = value;
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość pola Text Encoding jako zdekodowany sposób kodowania
        /// </summary>
        public string sTextEncoding
        {
            get
            {
                lock (olock)
                {
                    return mobiHdr.sTextEncoding;
                }
            }
        }
        //
        //
        /// <summary>
        /// zwraca zawartość pola Locale
        /// wpisuje do tego pola symbol literowy lub numeryczny języka
        ///[Angielski]= en= 9
        ///[Polski]= pl= 21
        ///[Angielski (USA)]= en-US= 1033
        ///[Polski (Polska)]= pl-PL= 1045
        /// 
        /// </summary>
        public int Locale
        {
            get
            {
                lock (olock)
                {
                    return mobiHdr.Locale;
                }
            }
            set
            {
                lock (olock)
                {
                    mobiHdr.IsDirty = true;
                    mobiHdr.Locale = value;
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość pola sLocale jako zdekodowane oznaczenie języka
        /// </summary>
        public string sLocale
        {
            get
            {
                lock (olock)
                {
                    return mobiHdr.sLocale;
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość pola sLocale jako zdekodowane oznaczenie języka
        /// </summary>
        public string sLocaleShort
        {
            get
            {
                lock (olock)
                {
                    return LanguageCodes.ToTextShort(mobiHdr.Locale);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość pola InputLanguage
        /// wpisuje do tego pola ()
        /// pole to używane jest wyłącznie przez słowniki
        /// </summary>
        public int InputLanguage
        {
            get
            {
                lock (olock)
                {
                    return mobiHdr.InputLanguage;
                }
            }
            set
            {
                lock (olock)
                {
                    mobiHdr.IsDirty = true;
                    mobiHdr.InputLanguage = value;
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość pola sInputLanguage jako zdekodowane oznaczenie języka
        /// pole to używane jest wyłącznie przez słowniki
        ///[Angielski]= en= 9
        ///[Polski]= pl= 21
        ///[Angielski (USA)]= en-US= 1033
        ///[Polski (Polska)]= pl-PL= 1045
        /// </summary>
        public string sInputLanguage
        {
            get
            {
                lock (olock)
                {
                    return mobiHdr.sInputLanguage;
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość pola OutputLanguage
        /// wpisuje do tego pola ()
        /// pole to używane jest wyłącznie przez słowniki
        /// </summary>
        public int OutputLanguage
        {
            get
            {
                lock (olock)
                {
                    return mobiHdr.OutputLanguage;
                }
            }
            set
            {
                lock (olock)
                {
                    mobiHdr.IsDirty = true;
                    mobiHdr.OutputLanguage = value;
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość pola OutputLanguage jako zdekodowane oznaczenie języka
        /// pole to używane jest wyłącznie przez słowniki
        ///[Angielski]= en= 9
        ///[Polski]= pl= 21
        ///[Angielski (USA)]= en-US= 1033
        ///[Polski (Polska)]= pl-PL= 1045
        /// </summary>
        public string sOutputLanguage
        {
            get
            {
                lock (olock)
                {
                    return mobiHdr.sOutputLanguage;
                }
            }
        }
        //
        //==================================================================================================================================
        //==================================================================================================================================
        //
        public bool IsEXTH
        {
            get
            {
                return null != exthHdr;
            }
        }
        //
        public bool IsFullName
        {
            get
            {
                return null != mfn;
            }
        }
        //
        /// <summary>
        /// Usuwa z EXTH rekord typu 'type'
        /// </summary>
        /// <param name="type"></param>
        internal void __deleteType(int type)
        {
            if (null != exthHdr) { exthHdr.deleteType(type); exthHdr.IsDirty = true; ;}
        }
        //
        //----------------------------------------------------------------------------------------------------------------------------------
        //
        internal bool __exthSetBytes(int type, byte[] value)
        {
            if (null == exthHdr) return false;
            exthHdr.IsDirty = true;// jeżeli !ExpandEXTH() to ustawienie jest fałszywe
            //
            int n = exthHdr.findType(type);
            if (n < 0)//nie ma
            {
                if(exthHdr.freeBytes() > value.Length + exthHdr.RECORD_HEADER_SIZE)
                {
                    //mieści się
                    n = exthHdr.addRecord(type, value.Length);
                }
                else
                {
                    //nie mieści się
                    //rozszerzyć EXTH
                    if (!ExpandEXTH(exthHdr.mb.Length + (exthHdr.RECORD_HEADER_SIZE + value.Length - exthHdr.freeBytes()))) return false;
                    n = exthHdr.addRecord(type, value.Length);
                }
            }
            else
            {
                int j = exthHdr.needBytes(n, value.Length);
                if (j > 0)
                {
                    //rozszerzyć EXTH
                    if (!ExpandEXTH(exthHdr.mb.Length + j)) return false;
                    exthHdr.expandRecordData(n, j);
                }
                else if (j < 0)
                {
                    exthHdr.contractRecordData(n, j);
                }
            }
            //
            exthHdr.setBytes(n, value);
            //
            return true;
        }
        //
        //----------------------------------------------------------------------------------------------------------------------------------
        //
        internal bool __exthSetNumber(int type, object value)
        {
            if (null == exthHdr) return false;
            exthHdr.IsDirty = true;// jeżeli !ExpandEXTH() to ustawienie jest fałszywe
            //
            int dataLength = 0;
            switch (value.GetType().Name)
            {
                case "Int32":
                    dataLength = 4;
                    break;
                case "Int16":
                    dataLength = 2;
                    break;
                case "Byte":
                    dataLength = 1;
                    break;
                default:
                    return false;
            }
            //
            int n = exthHdr.findType(type);
            if (n < 0)//nie ma
            {
                //rozszerzyć EXTH
                if (!ExpandEXTH(exthHdr.mb.Length + exthHdr.RECORD_HEADER_SIZE + dataLength)) return false;
                n = exthHdr.addRecord(type, dataLength);
            }
            else
            {
                int j = exthHdr.needBytes(n, dataLength);
                if (j > 0)
                {
                    //rozszerzyć EXTH
                    if (!ExpandEXTH(exthHdr.mb.Length + j)) return false;
                    exthHdr.expandRecordData(n, dataLength);
                }
                else if (j < 0)
                {
                    exthHdr.contractRecordData(n, dataLength);
                }
            }
            //
            switch (value.GetType().Name)
            {
                case "Int32":
                    exthHdr.setInt(n, (int)value);
                    break;
                case "Int16":
                    exthHdr.setShort(n, (short)value);
                    break;
                case "Byte":
                    exthHdr.setByte(n, (byte)value);
                    break;
            }
            //
            return true;
        }
        //
        //==================================================================================================================================
        //
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type">type of EXTH record</param>
        /// <param name="value">Byte,Int16,Int32</param>
        /// <returns></returns>
        public bool _exthSetNumber(int type, object value)
        {
            lock (olock)
            {
                return __exthSetNumber(type, value);
            }
        }
        //
        public bool _exthSetString(int type, string s)
        {
            lock (olock)
            {
                return __exthSetBytes(type, String2ByteArray(s.Trim().Replace("  ", " ")));
                //return _exthSetBytes(type, String2ByteArray(s+"\x00"));//stringi bez zerowych bajtów?
            }
        }
        //
        /*
        public bool _exthSetStringAsBytes(int type, string s)
        {
            lock (olock)
            {
                return __exthSetBytes(type, String2ByteArray(s.Trim()));
            }
        }
         */
        //
        //==================================================================================================================================
        //
        /// <summary>
        /// dla podanego 'type' zwraca bajty danych z EXTH. Jeżeli taki rekord nie istnieje - zwraca null
        /// null jest także zwracany przy braku EXTH
        /// </summary>
        /// <param name="type">record type</param>
        /// <returns><tablca bajtów z danymi tego rekordu, lub null/returns>
        public byte[] _exthGetBytes(int type)
        {
            if (null == exthHdr) return null;
            lock (olock)
            {
                if (null == exthHdr) return null;
                int n = exthHdr.findType(type);
                if (n < 0)//nie ma
                {
                    return null;
                }
                //
                return exthHdr.getBytesParameter(n);
            }
        }
        //
        public string _exthGetString(int type)
        {
            if (null == exthHdr) return "";
            lock (olock)
            {
                if (null == exthHdr) return null;
                int n = exthHdr.findType(type);
                if (n < 0)//nie ma
                {
                    return null;
                }
                //
                return exthHdr.getStringParameter(n);
            }
        }
        //
        public int? _exthGetInt(int type)
        {
            lock (olock)
            {
                if (null == exthHdr) return null;
                int n = exthHdr.findType(type);
                if (n < 0)//nie ma
                {
                    return null;
                }
                //
                return exthHdr.getIntParameter(n);
            }
        }
        //
        public short? _exthGetShort(int type)
        {
            lock (olock)
            {
                if (null == exthHdr) return null;
                int n = exthHdr.findType(type);
                if (n < 0)//nie ma
                {
                    return null;
                }
                //
                return exthHdr.getShortParameter(n);
            }
        }
        //
        public byte? _exthGetByte(int type)
        {
            lock (olock)
            {
                int n = exthHdr.findType(type);
                if (n < 0)//nie ma
                {
                    return null;
                }
                //
                return exthHdr.getByteParameter(n);
            }
        }
        //
        //==================================================================================================================================
        //
        public int exthRecordCount
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return 0;
                    return exthHdr.RecordCount;
                }
            }
        }
        //
        public int[] exthGetTypes
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return new int[] {};
                    return exthHdr.recordsTypes();
                }
            }
        }
        //
        public IEnumerable<exthRecordAsText> EnumAll
        {
            get
            {
                lock (olock)
                {
                    for (int k = 0; k < exthHdr.RecordCount; k++)
                    {
                        yield return new exthRecordAsText(k, exthHdr[k]);
                    }
                }
            }
        }

        //
        //==================================================================================================================================
        //==================================================================================================================================
        /// <summary>
        /// Usuwa z EXTH rekord typu 'type'
        /// </summary>
        /// <param name="type"></param>
        public void exthDeleteType(int type)
        {
            lock (olock)
            {
                __deleteType(type);
            }
        }
        //
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 100 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// Kindle: author
        /// </summary>
        public string exthAuthor//Kindle
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(100);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(100); return; }
                    _exthSetString(100, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 101 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthPublisher
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(101);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(101); return; }
                    _exthSetString(101, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 102 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthImprint
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(102);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(102); return; }
                    _exthSetString(102, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 103 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthDescription
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(103);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(103); return; }
                    _exthSetString(103, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 104 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthIsbn
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(104);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(104); return; }
                    _exthSetString(104, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu 105 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// Calibre: Tags
        /// </summary>
        public string exthSubject
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(105);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(105); return; }
                    _exthSetString(105, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 106 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthPublishingDate
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(106);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(106); return; }
                    _exthSetString(106, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 107 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthReview
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(107);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(107); return; }
                    _exthSetString(107, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 108 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthContributor
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(108);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(108); return; }
                    _exthSetString(108, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 109 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthRights
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(109);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(109); return; }
                    _exthSetString(109, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 110 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthSubjectCode
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(110);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(110); return; }
                    _exthSetString(110, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 111 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthType
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(111);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(111); return; }
                    _exthSetString(111, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 112 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthSource
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(112);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(112); return; }
                    _exthSetString(112, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 113 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthAsin
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(113);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(113); return; }
                    _exthSetString(113, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 115 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public int? exthSample
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getIntParameter(115);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(115); return; }
                    __exthSetNumber(115, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 117 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthAdult
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(117);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(117); return; }
                    _exthSetString(117, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 118 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthRetailPrice
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(118);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(118); return; }
                    _exthSetString(118, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 119 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthRetailPriceCurrency
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(119);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(119); return; }
                    _exthSetString(119, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 200 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthDictionaryShortName
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(200);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(200); return; }
                    _exthSetString(200, value);
                }
            }
        }
        //
#if false
        /// <summary>
        /// zwraca zawartość rekordu typu 201 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public int? exthCoverOffset
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getIntParameter(201);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { _deleteType(201); return; }
                    _exthSetNumber(201, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 202 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public int? exthThumbOffset
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getIntParameter(202);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { _deleteType(202); return; }
                    _exthSetNumber(202, value);
                }
            }
        }
#endif
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 204 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public int? exthCreatorSoftware
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getIntParameter(204);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(204); return; }
                    __exthSetNumber(204, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 205 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public int? exthCreatorMajorVersion
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getIntParameter(205);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(205); return; }
                    __exthSetNumber(205, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 206 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public int? exthCreatorMinorVersion
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getIntParameter(206);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(206); return; }
                    __exthSetNumber(206, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 207 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public int? exthCreatorBuildNumber
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getIntParameter(207);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(207); return; }
                    __exthSetNumber(207, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 401 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public byte? exthClippingLimit
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getByteParameter(401);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(401); return; }
                    __exthSetNumber(401, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 404 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public byte? exthttsFlag
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getByteParameter(404);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(404); return; }
                    __exthSetNumber(404, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 501 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthCdeType
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(501);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(501); return; }
                    _exthSetString(501, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu typu 502 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// </summary>
        public string exthLastUpdateTime
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(502);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(502); return; }
                    _exthSetString(502, value);
                }
            }
        }
        //
        /// <summary>
        /// zwraca zawartość rekordu 503 z EXTH Header, null gdy on nie istnieje
        /// wpisuje do tego rekordu, wpisanie null powoduje usuniecie tego rekordu
        /// Kindle: title
        /// </summary>
        public string exthUpdatedTitle
        {
            get
            {
                lock (olock)
                {
                    if (null == exthHdr) return null;
                    return exthHdr.getStringParameter(503);
                }
            }
            set
            {
                lock (olock)
                {
                    if (null == value) { __deleteType(503); return; }
                    _exthSetString(503, value);
                }
            }
        }
        //
        //==================================================================================================================================
        //==================================================================================================================================
        //
        public int exthDeleteExcept(int[] types)
        {
            if (null == exthHdr) return 0;
            //
            lock (olock)
            {
                int[] rr = (from r in exthHdr.EnumAll where !types.Contains(r.Type) select r.Type).ToArray<int>();
                if (0 != rr.Count()) exthHdr.IsDirty = true;
                rr.ForAll(r => exthHdr.deleteType(r));
                //
                return rr.Count();
            }
        }
        //
        //
        /// <summary>
        /// Kasuje całą zawartość bloku EXTH
        /// </summary>
        public void exthClear()
        {
            if (null == exthHdr) return;
            //
            lock (olock)
            {
                exthHdr.IsDirty = true;
                exthHdr.offsets.Clear();
                Array.Clear(exthHdr.mb.Buffer, exthHdr.HEADER_SIZE, (exthHdr.mb.Length- exthHdr.HEADER_SIZE));
                exthHdr.RecordCount = 0;
            }
        }
        //
        public void exthDeleteDoubles()
        {
            if (null == exthHdr) return;
            //
            lock (olock)
            {
                if(exthHdr.deleteDoubles())exthHdr.IsDirty = true;
            }
        }
        //
        //==================================================================================================================================
    }//class
}//namespace
